package com.xujiahong.codegenerator;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.xujiahong.codegenerator.dao.CodeGenerateDao;
import com.xujiahong.codegenerator.entity.XColumn;
import com.xujiahong.codegenerator.entity.XTable;
import com.xujiahong.codegenerator.template.CreateEntity;
import com.xujiahong.codegenerator.template.CreateMockJson;
import com.xujiahong.codegenerator.template.CreateTestJson;
import com.xujiahong.codegenerator.tools.ParsecFileTools;
import com.xujiahong.codegenerator.tools.XParseName;
import com.xujiahong.codegenerator.tools.XParseTemplate;
import com.xujiahong.codegenerator.tools.XParseType;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 代码生成器
 * Created by xujiahong on 2017/8/3.
 * ======================功能列表======================
 */
public class CodeGenerator {

    static CodeGenerateDao dao;
    static SqlSession session;

    static {
        //读取配置
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
        } catch (IOException e) {
            e.printStackTrace();
            throw new IllegalArgumentException("读取mybatis配置文件出错");
        }
        //获取sqlSession，实例化查询接口
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        session = sqlSessionFactory.openSession();
        dao = session.getMapper(CodeGenerateDao.class);
    }


    public static void main(String[] args) {

        System.out.println("开始生成代码");

        List<XTable> tables = getAllTable();

        // 整库代码生成
        generatorBaseCode(tables);

        // 数据库表设计一览（markdown表格）
//        MarkdownTable.create(tables);

        // 导出数据库excel
//        export();

        session.close();
    }

    // 整库代码生成
    public static void generatorBaseCode(List<XTable> tables){
        for (XTable xTable : tables) {
            try {
                createFile(xTable);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    // 导出excel，全表
    public static void export() {
        try (ExcelWriter writer = ExcelUtil.getWriter(Config.CODE_PATH + Config.DATABASE_NAME + "_" + System.currentTimeMillis() + ".xlsx")) {

            //自定义别名和字段顺序
            writer.setOnlyAlias(true);
            //自定义标题别名
            writer.addHeaderAlias("列名", "字段名");
            writer.addHeaderAlias("数据类型", "数据类型");
            writer.addHeaderAlias("字段长度", "字段长度");
            writer.addHeaderAlias("是否必填", "是否必填");
            writer.addHeaderAlias("备注", "备注");

            writer.setColumnWidth(0, 20);
            writer.setColumnWidth(1, 20);
            writer.setColumnWidth(2, 20);
            writer.setColumnWidth(3, 20);
            writer.setColumnWidth(4, 50);

            String[] header = {"字段名", "数据类型", "字段长度", "是否必填", "备注"};

            List<XTable> tables = getAllTable();
            for (XTable xTable : tables) {
                // 跳过migration表
                if ("flyway_schema_history".equals(xTable.getTableName()) ||
                        "schema_version".equals(xTable.getTableName())) {
                    continue;
                }
                export(writer, xTable, header);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 导出excel，单表
    public static void export(ExcelWriter writer, XTable xTable, String[] header) {
        List<Map<String, String>> list = dao.selectTableInfo(Config.DATABASE_NAME, xTable.getTableName());

        writer.passCurrentRow();
        writer.merge(4, xTable.getTableName() + "_" + xTable.getChName());
        writer.writeHeadRow(Arrays.asList(header));
        writer.write(list);
    }

    /**
     * 根据实际配置，生成各种文件
     *
     * @param xTable
     * @throws Exception
     */
    public static void createFile(XTable xTable) throws Exception {

        // 生成实体
        CreateEntity.createMybatisPlusEntity(xTable);
        // 生成Json
        CreateTestJson.createJson(xTable);
        CreateMockJson.createJson(xTable);
        // 生成Mapper
        ParsecFileTools.writeFile(Config.CODE_PATH + "mapper/" + xTable.getPojoName() + "Mapper.java", XParseTemplate.scan("parsec/MybatisPlusMapper.txt", xTable));
        // 生成Service
        ParsecFileTools.writeFile(Config.CODE_PATH + "service/" + xTable.getPojoName() + "Service.java", XParseTemplate.scan("parsec/Service.txt", xTable));
        ParsecFileTools.writeFile(Config.CODE_PATH + "service/impl/" + xTable.getPojoName() + "ServiceImpl.java", XParseTemplate.scan("parsec/ServiceImpl.txt", xTable));
        // 生成Controller
        ParsecFileTools.writeFile(Config.CODE_PATH + "endpoint/" + xTable.getPojoName() + "MchController.java", XParseTemplate.scan("chisAlphaController.txt", xTable));
//        //生成ApiController
//        ParsecFileTools.writeFile(Config.CODE_PATH + "controller/api/" + xTable.getPojoName() + "ApiController.java", XParseTemplate.scan("parsec/ApiController.txt", xTable));
//        //生成MgrController
//        ParsecFileTools.writeFile(Config.CODE_PATH + "controller/mgr/" + xTable.getPojoName() + "MgrController.java", XParseTemplate.scan("parsec/MgrController.txt", xTable));

    }

    /**
     * 获取表信息
     *
     * @param tableName
     * @param chName
     * @return XTable
     */
    public static XTable getTable(String tableName, String chName) {
        if (tableName == null || "".equals(tableName) || chName == null || "".equals(chName)) {
            throw new IllegalArgumentException("入参异常");
        }

        //查询数据表的Fields
        List<Map<String, Object>> list = dao.showFullFields(tableName);
        if (list == null || list.size() == 0) {
            throw new IllegalArgumentException("数据表字段为空");
        }
        List<XColumn> columns = new ArrayList<XColumn>();
        for (Map<String, Object> map : list) {
            if (map != null) {
                XColumn xColumn = new XColumn();
                if (map.containsKey("Field")) {
                    xColumn.setDbFieldName(map.get("Field").toString());
                    xColumn.setJavaFieldName(XParseName.parseNameToCamel(map.get("Field").toString()));
                }
                if (map.containsKey("Type")) {
                    xColumn.setDbFieldType(XParseType.parseType(map.get("Type").toString()));
                    xColumn.setJavaFieldType(XParseType.parseTypeToJava(map.get("Type").toString()));
                }
                if (map.containsKey("Comment")) {
                    xColumn.setComment(map.get("Comment").toString());
                }
                columns.add(xColumn);
            }
        }
        //创建表对象
        XTable xTable = new XTable(tableName, chName, columns);
        System.out.println("获取数据表" + tableName + "信息成功");
        return xTable;
    }


    /**
     * 获取所有表信息
     */
    public static List<XTable> getAllTable() {
        List<XTable> list = new ArrayList<>();
        List<Map<String, String>> tables = dao.selectTables(Config.DATABASE_NAME);
        for (Map<String, String> map : tables) {
            String tableName = map.get("tableName");
            String tableComment = map.get("tableComment");
            if (tableComment == null || "".equals(tableComment)) {
                tableComment = tableName;
            }
//            if (tableName.equals("tbl_acl") || tableName.equals("tbl_directory")) {
//                continue;
//            }
            XTable xTable = getTable(tableName, tableComment);
            list.add(xTable);
        }

        if (CollectionUtil.isEmpty(list)) {
            System.err.println(Config.DATABASE_NAME + " 数据库中没有检测到任何表");
        }
        return list;
    }

}
